#pragma once

const int MAX_CONFIG_NAME_LENGTH = 50;

enum CONFIG_TOKEN
{
	TOKEN_NONE,
	TOKEN_ENDLINE,
	TOKEN_EQUAL,
	TOKEN_SECTION,
	TOKEN_VARIABLE,
	TOKEN_EOF,
	TOKEN_ROOT
};

class TokenNode
{
public:
	TokenNode(CONFIG_TOKEN _token, const char* _data) 
	{ 
		token = _token;
		if (_data)
		{
			data = new char[MAX_CONFIG_NAME_LENGTH];
			strcpy_s(data, MAX_CONFIG_NAME_LENGTH, _data);
		}
		else
		{
			data = NULL;
		}
	}

	~TokenNode() 
	{
		// delete data
		if (data)
		{
			delete[] data;
		}

		// delete all children
		std::vector<const TokenNode*>::iterator iter = children.begin();
		for (; iter != children.end(); ++iter)
		{
			if (*iter)
			{
				delete (*iter);
			}
		}

		children.clear();
	}

	void addChild(const TokenNode* node)
	{
		if (node != NULL)
		{
			children.push_back(node);
		}
	}

	const TokenNode* getChild(size_t index) const 
	{ 
		if (index >= 0 && index < children.size())
		{
			return children[index]; 
		}

		return NULL;
	}

	CONFIG_TOKEN getToken() const { return token; }
	const char* getData() const { return data; }
	size_t getNumChildren() const { return children.size(); }
private:
	CONFIG_TOKEN token;
	char* data;
	std::vector<const TokenNode*> children;
};

class ConfigParser
{
public:
	ConfigParser(const std::string& fileName);
	~ConfigParser(void);

	void parse();
	const char* getFirstValueByName(const std::string& name, const char* sectionName) const;
	void getAllValuesByName(const std::string& name, const char* sectionName, char** outValues) const;
private:
	TokenNode* readNextToken();
	void parseSection(TokenNode* section);
	void parseExpression(TokenNode* father, TokenNode* lChild, TokenNode* rChild);

	bool isLegalExpression(const char& ch) const;

	const TokenNode* search(const std::string& name, const char* sectionName) const;
private:
	std::fstream currentFile;
	char nextChar;

	TokenNode* currentRoot;
	TokenNode* defaultSection;
	TokenNode* currentNode;
};